<template>
  <van-form :label-width="labelWidth" @submit="onSubmit" safe-area-inset-bottom>
    <van-cell-group inset>
      <template v-for="(item, index) in options" :key="index">
        <!-- 输入框 -->
        <van-field
          v-if="item.type === 'field'"
          :label-align="labelAlign"
          v-model="form[item.key]"
          :label="item.label"
          :name="item.key"
          :placeholder="
            readonly || item.disabled
              ? ''
              : item.placeholder || `填写${item.label}${item.rules?.find(i => i.required === true) ? '（必填）' : ''}`
          "
          :clearable="clearable"
          :maxlength="readonly ? undefined : item.maxlength || 30"
          :rules="item.rules"
          :readonly="readonly || item.disabled"
        />
        <!-- 大输入框 -->
        <van-field
          v-if="item.type === 'textarea'"
          :label-align="labelAlign"
          type="textarea"
          :rows="readonly ? 1 : 3"
          autosize
          :show-word-limit="!readonly && !item.disabled"
          v-model="form[item.key]"
          :label="item.label"
          :name="item.key"
          :placeholder="
            readonly || item.disabled
              ? ''
              : item.placeholder || `填写${item.label}${item.rules?.find(i => i.required === true) ? '（必填）' : ''}`
          "
          :clearable="clearable"
          :maxlength="readonly ? undefined : item.maxlength || 140"
          :rules="item.rules"
          :readonly="readonly || item.disabled"
        />
        <!-- 选择器 -->
        <van-field
          v-if="item.type === 'picker'"
          :label-align="labelAlign"
          v-model="form[item.key]"
          :label="item.label"
          :name="item.key"
          :placeholder="
            readonly || item.disabled
              ? ''
              : item.placeholder || `选择${item.label}${item.rules?.find(i => i.required === true) ? '（必填）' : ''}`
          "
          :clearable="clearable"
          :rules="item.rules"
          :is-link="!readonly"
          readonly
          @click="onShowPicker(readonly, item.key)"
          @clear="onPickerClear(item.key)"
        />
        <van-popup
          v-if="item.type === 'picker'"
          v-model:show="showPicker[item.key]"
          position="bottom"
          safe-area-inset-bottom
        >
          <van-picker
            :columns="item.columns"
            :loading="item.loading"
            @confirm="res => onConfirm(res, item)"
            @cancel="showPicker[item.key] = false"
          >
            <template v-if="item.filter" #title>
              <van-field
                class="picker-filter"
                v-model="form[item.key + 'KeyWord']"
                placeholder="输入关键字模糊搜索"
                :maxlength="10"
              />
            </template>
          </van-picker>
        </van-popup>
        <!-- 单个日期 -->
        <van-field
          v-if="item.type === 'calendar'"
          :label-align="labelAlign"
          v-model="form[item.key]"
          :label="item.label"
          :name="item.key"
          :placeholder="
            readonly || item.disabled
              ? ''
              : item.placeholder || `选择${item.label}${item.rules?.find(i => i.required === true) ? '（必填）' : ''}`
          "
          :clearable="clearable"
          :rules="item.rules"
          :is-link="!readonly"
          readonly
          @click="onShowPicker(readonly, item.key)"
          @clear="onPickerClear(item.key)"
        />
        <van-calendar
          v-if="item.type === 'calendar'"
          v-model:show="showPicker[item.key]"
          @confirm="res => onCalendarConfirm(res, item)"
          safe-area-inset-bottom
        />
        <!-- 多个日期 -->
        <van-field
          v-if="item.type === 'multiple-calendar'"
          :label-align="labelAlign"
          v-model="form[item.key]"
          :label="item.label"
          :name="item.key"
          :placeholder="
            readonly || item.disabled
              ? ''
              : item.placeholder || `选择${item.label}${item.rules?.find(i => i.required === true) ? '（必填）' : ''}`
          "
          :clearable="clearable"
          :rules="item.rules"
          :is-link="!readonly"
          readonly
          @click="onShowPicker(readonly, item.key)"
          @clear="onPickerClear(item.key)"
        />
        <van-calendar
          v-if="item.type === 'multiple-calendar'"
          v-model:show="showPicker[item.key]"
          type="multiple"
          @confirm="res => onCalendarConfirm(res, item)"
          safe-area-inset-bottom
        />
        <!-- 区间日期 -->
        <van-field
          v-if="item.type === 'range-calendar'"
          :label-align="labelAlign"
          v-model="form[item.key]"
          :label="item.label"
          :name="item.key"
          :placeholder="
            readonly || item.disabled
              ? ''
              : item.placeholder || `选择${item.label}${item.rules?.find(i => i.required === true) ? '（必填）' : ''}`
          "
          :clearable="clearable"
          :rules="item.rules"
          :is-link="!readonly"
          readonly
          @click="onShowPicker(readonly, item.key)"
          @clear="onPickerClear(item.key)"
        />
        <van-calendar
          v-if="item.type === 'range-calendar'"
          v-model:show="showPicker[item.key]"
          type="range"
          @confirm="res => onCalendarConfirm(res, item)"
          safe-area-inset-bottom
        />
        <!-- 文件上传 -->
        <van-field v-if="item.type === 'upload'" :label="item.label" :name="item.key">
          <template #input>
            <van-uploader
              v-model="fileList[item.key]"
              :after-read="file => afterRead(file, item.key)"
              :accept="item.accept"
              :multiple="item.multiple || true"
              :max-count="item.maxCount || 10"
              :max-size="5120 * 1024"
              :readonly="readonly || item.disabled"
              :disabled="readonly || item.disabled"
            />
          </template>
        </van-field>
      </template>
    </van-cell-group>
    <div v-if="!readonly" class="btn">
      <van-button round block type="primary" native-type="submit" :disabled="loading"> {{ submitText }} </van-button>
      <van-button v-if="reset" round block type="default" class="reset" @click="onReset"> 重置 </van-button>
    </div>
  </van-form>
</template>

<script setup>
  import dayjs from 'dayjs'
  import {onMounted} from 'vue'
  const emit = defineEmits(['submit', 'reset', 'uploadOk', 'update:form'])
  const props = defineProps({
    labelWidth: {
      type: [Number, String],
      default: '6.75em',
    },
    labelAlign: {
      type: String,
      default: 'left',
    },
    options: {
      type: Array,
      default: () => [],
    },
    form: {
      type: Object,
      default: () => {
        return {}
      },
    },
    submitText: {
      type: String,
      default: '提交',
    },
    readonly: {
      type: Boolean,
      default: false,
    },
    clearable: {
      type: Boolean,
      default: false,
    },
    reset: {
      type: Boolean,
      default: false,
    },
    loading: {
      type: Boolean,
      default: false,
    },
  })
  const fileList = reactive({})
  const showPicker = reactive({})
  const initFileList = () => {
    const keyList = props.options?.filter(item => item.type === 'upload')?.map(item => item.key)
    keyList.forEach(key => {
      if (props.form[key]) {
        if (Array.isArray(props.form[key])) {
          fileList[key] = props.form[key].map(item => {
            return {
              url: item,
            }
          })
        } else {
          fileList[key] = [{url: props.form[key]}]
        }
      }
    })
  }
  const onShowPicker = (readonly, key) => {
    if (!readonly) {
      showPicker[key] = true
    }
  }
  const onPickerClear = item => {
    console.log(item)
  }
  const onConfirm = (res, item) => {
    props.form[item.key] = res.selectedOptions[0].text
    props.form[item.key + 'Value'] = res.selectedOptions[0].value
    props.form[item.key + 'KeyWord'] = undefined
    showPicker[item.key] = false
  }
  const afterRead = (files, key) => {
    const formData = new FormData()
    if (Array.isArray(files)) {
      files.forEach(item => {
        item.status = 'uploading'
        item.message = '上传中...'
        formData.append('multipartFiles', item.file)
      })
    } else {
      files.status = 'uploading'
      files.message = '上传中...'
      formData.append('uploadStrategy', 'Oss')
      formData.append('multipartFiles', files.file)
    }
    $post('/bus/api/v1/file/upload', formData, {
      headers: {'Content-Type': 'multipart/form-data'},
    })
      .then(res => {
        const {data} = res
        if (Array.isArray(files)) {
          files.forEach(item => {
            item.status = 'done'
            item.message = '上传成功'
            item.url = data.find(i => i.fileName === item.file.name)?.url
          })
        } else {
          files.status = 'done'
          files.message = '上传成功'
          files.url = data.find(i => i.fileName === files.file.name)?.url
        }
        emit('uploadOk', fileList)
      })
      .catch(() => {
        if (Array.isArray(files)) {
          files.forEach(item => {
            item.status = 'failed'
            item.message = '上传失败'
          })
        } else {
          files.status = 'failed'
          files.message = '上传失败'
        }
      })
  }
  const onCalendarConfirm = (res, item) => {
    if (Array.isArray(res)) {
      props.form[item.key + 'Array'] = res.map(item => dayjs(item).format('YYYY-MM-DD'))
      props.form[item.key] = res.map(item => dayjs(item).format('YYYY-MM-DD')).join(',')
    } else {
      props.form[item.key] = dayjs(res).format('YYYY-MM-DD')
    }
    showPicker[item.key] = false
  }
  const onSubmit = () => {
    emit('submit')
  }
  const onReset = () => {
    emit('update:form', formCache)
    emit('reset')
  }
  let formCache = {}
  onMounted(() => {
    formCache = JSON.parse(JSON.stringify(toRaw(props.form)))
    initFileList()
  })
</script>

<style lang="scss" scoped>
  :deep(.picker-filter) {
    width: calc(100% - 280px);
    input {
      text-align: center;
    }
  }
  .van-cell {
    font-size: 30px;
  }
  .van-cell-group--inset {
    padding-bottom: calc(180px + 64px + 48px);
  }
  .btn {
    position: fixed;
    bottom: 0;
    width: calc(100% - 32px - 32px);
    margin: 32px;
  }
  .reset {
    margin-top: 24px;
  }
</style>
